﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace LinAlg3D
{
    /// <summary>
    /// Describes and manipulates a 4x4 matrix.
    /// </summary>
    [Serializable()]
    public struct Matrix
    {
        private float m11;
        private float m12;
        private float m13;
        private float m14;

        private float m21;
        private float m22;
        private float m23;
        private float m24;

        private float m31;
        private float m32;
        private float m33;
        private float m34;

        private float m41;
        private float m42;
        private float m43;
        private float m44;

        // Properties

        #region Columns
        /// <summary>
        /// Retrieves the first column of the Matrix matrix.
        /// </summary>
        public Vector4 Col1 { get { return new Vector4(M11, M21, M31, M41); } }
        /// <summary>
        /// Retrieves the second column of the Matrix matrix.
        /// </summary>
        public Vector4 Col2 { get { return new Vector4(M12, M22, M32, M42); } }
        /// <summary>
        /// Retrieves the third column of the Matrix matrix.
        /// </summary>
        public Vector4 Col3 { get { return new Vector4(M13, M23, M33, M43); } }
        /// <summary>
        /// Retrieves the fourth column of the Matrix matrix.
        /// </summary>
        public Vector4 Col4 { get { return new Vector4(M14, M24, M34, M44); } }
        #endregion

        #region Determinant
        /// <summary>
        /// Retrieves the determinant of this matrix.
        /// </summary>
        public float Determinant
        {
            get
            {
                float result = 0;

                float t01 = m11 * m22 * m33 * m44;
                float t02 = m11 * m23 * m34 * m42;
                float t03 = m11 * m24 * m32 * m43;

                float t04 = m12 * m21 * m34 * m43;
                float t05 = m12 * m23 * m31 * m44;
                float t06 = m12 * m24 * m33 * m41;

                float t07 = m13 * m21 * m32 * m44;
                float t08 = m13 * m22 * m34 * m41;
                float t09 = m13 * m24 * m31 * m42;

                float t10 = m14 * m21 * m33 * m42;
                float t11 = m14 * m22 * m31 * m43;
                float t12 = m14 * m23 * m32 * m41;

                float t13 = m11 * m22 * m34 * m43;
                float t14 = m11 * m23 * m32 * m44;
                float t15 = m11 * m24 * m33 * m42;

                float t16 = m12 * m21 * m33 * m44;
                float t17 = m12 * m23 * m34 * m41;
                float t18 = m12 * m24 * m31 * m43;

                float t19 = m13 * m21 * m34 * m42;
                float t20 = m13 * m22 * m31 * m44;
                float t21 = m13 * m24 * m32 * m41;

                float t22 = m14 * m21 * m32 * m43;
                float t23 = m14 * m22 * m33 * m41;
                float t24 = m14 * m23 * m31 * m42;

                result = t01 + t02 + t03 + t04 +
                            t05 + t06 + t07 + t08 +
                            t09 + t10 + t11 + t12 -
                            t13 - t14 - t15 - t16 -
                            t17 - t18 - t19 - t20 -
                            t21 - t22 - t23 - t24;

                return result;
            }
        }
        #endregion

        #region Fields
        /// <summary>
        /// Value at row 1 column 1 of the matrix.
        /// </summary>
        public float M11
        {
            get { return m11; }
            set { m11 = value; }
        }

        /// <summary>
        /// Value at row 1 column 2 of the matrix.
        /// </summary>
        public float M12
        {
            get { return m12; }
            set { m12 = value; }
        }

        /// <summary>
        /// Value at row 1 column 3 of the matrix.
        /// </summary>
        public float M13
        {
            get { return m13; }
            set { m13 = value; }
        }

        /// <summary>
        /// Value at row 1 column 4 of the matrix. 
        /// </summary>
        public float M14
        {
            get { return m14; }
            set { m14 = value; }
        }

        /// <summary>
        /// Value at row 2 column 1 of the matrix.
        /// </summary>
        public float M21
        {
            get { return m21; }
            set { m21 = value; }
        }

        /// <summary>
        /// Value at row 2 column 2 of the matrix.
        /// </summary>
        public float M22
        {
            get { return m22; }
            set { m22 = value; }
        }

        /// <summary>
        /// Value at row 2 column 3 of the matrix.
        /// </summary>
        public float M23
        {
            get { return m23; }
            set { m23 = value; }
        }

        /// <summary>
        /// Value at row 2 column 4 of the matrix.
        /// </summary>
        public float M24
        {
            get { return m24; }
            set { m24 = value; }
        }

        /// <summary>
        /// Value at row 3 column 1 of the matrix.
        /// </summary>
        public float M31
        {
            get { return m31; }
            set { m31 = value; }
        }

        /// <summary>
        /// Value at row 3 column 2 of the matrix.
        /// </summary>
        public float M32
        {
            get { return m32; }
            set { m32 = value; }
        }

        /// <summary>
        /// Value at row 3 column 3 of the matrix.
        /// </summary>
        public float M33
        {
            get { return m33; }
            set { m33 = value; }
        }
        /// <summary>
        /// Value at row 3 column 4 of the matrix.
        /// </summary>
        public float M34
        {
            get { return m34; }
            set { m34 = value; }
        }

        /// <summary>
        /// Value at row 4 column 1 of the matrix.
        /// </summary>
        public float M41
        {
            get { return m41; }
            set { m41 = value; }
        }

        /// <summary>
        /// Value at row 4 column 2 of the matrix.
        /// </summary>
        public float M42
        {
            get { return m42; }
            set { m42 = value; }
        }

        /// <summary>
        /// Value at row 4 column 3 of the matrix.
        /// </summary>
        public float M43
        {
            get { return m43; }
            set { m43 = value; }
        }

        /// <summary>
        /// Value at row 4 column 4 of the matrix.
        /// </summary>
        public float M44
        {
            get { return m44; }
            set { m44 = value; }
        }
        #endregion

        #region Identity
        /// <summary>
        /// Retrieves a 4x4 Identity matrix
        /// </summary>
        /// <returns>Matrix Identity matrix</returns>
        public static Matrix Identity
        {
            get
            {
                Matrix matrix;

                matrix.m11 = 1;
                matrix.m12 = 0;
                matrix.m13 = 0;
                matrix.m14 = 0;

                matrix.m21 = 0;
                matrix.m22 = 1;
                matrix.m23 = 0;
                matrix.m24 = 0;

                matrix.m31 = 0;
                matrix.m32 = 0;
                matrix.m33 = 1;
                matrix.m34 = 0;

                matrix.m41 = 0;
                matrix.m42 = 0;
                matrix.m43 = 0;
                matrix.m44 = 1;

                return matrix;
            }
        }
        #endregion

        #region Rows
        /// <summary>
        /// Retrieves the first row of the Matrix matrix.
        /// </summary>
        public Vector4 Row1 { get { return new Vector4(M11, M12, M13, M14); } }
        /// <summary>
        /// Retrieves the second row of the Matrix matrix.
        /// </summary>
        public Vector4 Row2 { get { return new Vector4(M21, M22, M23, M24); } }
        /// <summary>
        /// Retrieves the third row of the Matrix matrix.
        /// </summary>
        public Vector4 Row3 { get { return new Vector4(M31, M32, M33, M34); } }
        /// <summary>
        /// Retrieves the fourth row of the Matrix matrix.
        /// </summary>
        public Vector4 Row4 { get { return new Vector4(M41, M42, M43, M44); } }
        #endregion

        #region Zero
        /// <summary>
        /// Retrieves a 4x4 empty matrix
        /// </summary>
        /// <returns>Matrix Zero matrix</returns>
        public static Matrix Zero
        {
            get
            {
                Matrix matrix;

                matrix.m11 = 0;
                matrix.m12 = 0;
                matrix.m13 = 0;
                matrix.m14 = 0;

                matrix.m21 = 0;
                matrix.m22 = 0;
                matrix.m23 = 0;
                matrix.m24 = 0;

                matrix.m31 = 0;
                matrix.m32 = 0;
                matrix.m33 = 0;
                matrix.m34 = 0;

                matrix.m41 = 0;
                matrix.m42 = 0;
                matrix.m43 = 0;
                matrix.m44 = 0;

                return matrix;
            }
        }
        #endregion

        // Methods

        #region Addition

        /// <summary>
        /// Adds two 4x4 matrices.
        /// </summary>
        /// <param name="matrix1">Matrix source matrix.</param>
        /// <param name="matrix2">Matrix source matrix.</param>
        /// <returns>Matrix result matrix.</returns>
        public static Matrix Add(Matrix matrix1, Matrix matrix2)
        {
            Matrix result;
            result.m11 = matrix1.m11 + matrix2.m11;
            result.m12 = matrix1.m12 + matrix2.m12;
            result.m13 = matrix1.m13 + matrix2.m13;
            result.m14 = matrix1.m14 + matrix2.m14;

            result.m21 = matrix1.m21 + matrix2.m21;
            result.m22 = matrix1.m22 + matrix2.m22;
            result.m23 = matrix1.m23 + matrix2.m23;
            result.m24 = matrix1.m24 + matrix2.m24;

            result.m31 = matrix1.m31 + matrix2.m31;
            result.m32 = matrix1.m32 + matrix2.m32;
            result.m33 = matrix1.m33 + matrix2.m33;
            result.m34 = matrix1.m34 + matrix2.m34;

            result.m41 = matrix1.m41 + matrix2.m41;
            result.m42 = matrix1.m42 + matrix2.m42;
            result.m43 = matrix1.m43 + matrix2.m43;
            result.m44 = matrix1.m44 + matrix2.m44;

            return result;
        }



        #endregion

        #region Equals
        /// <summary>
        /// Returns a value that indicates whether the current instance is equal to a specified object.
        /// </summary>
        /// <param name="obj">Object with which to make the comparison.</param>
        /// <returns>Value that is true if the current instance is equal to the specified object, or false if it is not.</returns>
        public override bool Equals(object obj)
        {
            // If parameter is null return false.
            if (obj == null)
            {
                return false;
            }

            // If parameter cannot be cast to Vector3f return false.
            if (!(obj is Matrix))
            {
                return false;
            }

            // Return true if the fields match:
            return (m11 == ((Matrix)obj).m11 && m12 == ((Matrix)obj).m12 && m13 == ((Matrix)obj).m13 && m14 == ((Matrix)obj).m14 &&
                    m21 == ((Matrix)obj).m21 && m22 == ((Matrix)obj).m22 && m23 == ((Matrix)obj).m23 && m24 == ((Matrix)obj).m24 &&
                    m31 == ((Matrix)obj).m31 && m32 == ((Matrix)obj).m32 && m33 == ((Matrix)obj).m33 && m34 == ((Matrix)obj).m34 &&
                    m41 == ((Matrix)obj).m41 && m42 == ((Matrix)obj).m42 && m43 == ((Matrix)obj).m43 && m44 == ((Matrix)obj).m44);

        }
        #endregion

        #region GetHashCode
        /// <summary>
        /// Returns the hash code for the current instance.
        /// </summary>
        /// <returns>Hash code for the instance.</returns>
        public override int GetHashCode()
        {
            return m11.GetHashCode() ^
                    m12.GetHashCode() ^
                    m13.GetHashCode() ^
                    m14.GetHashCode() ^
                    m21.GetHashCode() ^
                    m22.GetHashCode() ^
                    m23.GetHashCode() ^
                    m24.GetHashCode() ^
                    m31.GetHashCode() ^
                    m32.GetHashCode() ^
                    m33.GetHashCode() ^
                    m34.GetHashCode() ^
                    m41.GetHashCode() ^
                    m42.GetHashCode() ^
                    m43.GetHashCode() ^
                    m44.GetHashCode();
        }
        #endregion

        #region Invert
        public static Matrix Invert(Matrix matrix)
        {
            Matrix m = matrix;
            float det = m.Determinant;

            Matrix result = new Matrix();

            if (det == 0)
                return Matrix.Zero;

            result.M11 = (m.M22 * m.M33 * m.M44) + (m.M23 * m.M34 * m.M42) + (m.M24 * m.M32 * m.M43) - (m.M22 * m.M34 * m.M43) - (m.M23 * m.M32 * m.M44) - (m.M24 * m.M33 * m.M42);
            result.M12 = (m.M12 * m.M34 * m.M43) + (m.M13 * m.M32 * m.M44) + (m.M14 * m.M33 * m.M42) - (m.M12 * m.M33 * m.M44) - (m.M13 * m.M34 * m.M42) - (m.M14 * m.M32 * m.M43);
            result.M13 = (m.M12 * m.M23 * m.M44) + (m.M13 * m.M24 * m.M42) + (m.M14 * m.M22 * m.M43) - (m.M12 * m.M24 * m.M43) - (m.M13 * m.M22 * m.M44) - (m.M14 * m.M23 * m.M42);
            result.M14 = (m.M12 * m.M24 * m.M33) + (m.M13 * m.M22 * m.M34) + (m.M14 * m.M23 * m.M32) - (m.M12 * m.M23 * m.M34) - (m.M13 * m.M24 * m.M32) - (m.M14 * m.M22 * m.M33);
            result.M21 = (m.M21 * m.M34 * m.M43) + (m.M23 * m.M31 * m.M44) + (m.M24 * m.M33 * m.M41) - (m.M21 * m.M33 * m.M44) - (m.M23 * m.M34 * m.M41) - (m.M24 * m.M31 * m.M43);
            result.M22 = (m.M11 * m.M33 * m.M44) + (m.M13 * m.M34 * m.M41) + (m.M14 * m.M31 * m.M43) - (m.M11 * m.M34 * m.M43) - (m.M13 * m.M31 * m.M44) - (m.M14 * m.M33 * m.M41);
            result.M23 = (m.M11 * m.M24 * m.M43) + (m.M13 * m.M21 * m.M44) + (m.M14 * m.M23 * m.M41) - (m.M11 * m.M23 * m.M44) - (m.M13 * m.M24 * m.M41) - (m.M14 * m.M21 * m.M43);
            result.M24 = (m.M11 * m.M23 * m.M34) + (m.M13 * m.M24 * m.M31) + (m.M14 * m.M21 * m.M33) - (m.M11 * m.M24 * m.M33) - (m.M13 * m.M21 * m.M34) - (m.M14 * m.M23 * m.M31);
            result.M31 = (m.M21 * m.M32 * m.M44) + (m.M22 * m.M34 * m.M41) + (m.M24 * m.M31 * m.M42) - (m.M21 * m.M34 * m.M42) - (m.M22 * m.M31 * m.M44) - (m.M24 * m.M32 * m.M41);
            result.M32 = (m.M11 * m.M34 * m.M42) + (m.M12 * m.M31 * m.M44) + (m.M14 * m.M32 * m.M41) - (m.M11 * m.M32 * m.M44) - (m.M12 * m.M34 * m.M41) - (m.M14 * m.M31 * m.M42);
            result.M33 = (m.M11 * m.M22 * m.M44) + (m.M12 * m.M24 * m.M41) + (m.M14 * m.M21 * m.M42) - (m.M11 * m.M24 * m.M42) - (m.M12 * m.M21 * m.M44) - (m.M14 * m.M22 * m.M41);
            result.M34 = (m.M11 * m.M24 * m.M32) + (m.M12 * m.M21 * m.M34) + (m.M14 * m.M22 * m.M31) - (m.M11 * m.M22 * m.M34) - (m.M12 * m.M24 * m.M31) - (m.M14 * m.M21 * m.M32);
            result.M41 = (m.M21 * m.M33 * m.M42) + (m.M22 * m.M31 * m.M43) + (m.M23 * m.M32 * m.M41) - (m.M21 * m.M32 * m.M43) - (m.M22 * m.M33 * m.M41) - (m.M23 * m.M31 * m.M42);
            result.M42 = (m.M11 * m.M32 * m.M43) + (m.M12 * m.M33 * m.M41) + (m.M13 * m.M31 * m.M42) - (m.M11 * m.M33 * m.M42) - (m.M12 * m.M31 * m.M43) - (m.M13 * m.M32 * m.M41);
            result.M43 = (m.M11 * m.M23 * m.M42) + (m.M12 * m.M21 * m.M43) + (m.M13 * m.M22 * m.M41) - (m.M11 * m.M22 * m.M43) - (m.M12 * m.M23 * m.M41) - (m.M13 * m.M21 * m.M42);
            result.M44 = (m.M11 * m.M22 * m.M33) + (m.M12 * m.M23 * m.M31) + (m.M13 * m.M21 * m.M32) - (m.M11 * m.M23 * m.M32) - (m.M12 * m.M21 * m.M33) - (m.M13 * m.M22 * m.M31);

            result = (1.0f / det) * result;
            return result;
        }
        #endregion

        #region Multiply
        /// <summary>
        /// Determines the product of two matrices.
        /// </summary>
        /// <param name="matrix1">Source Matrix matrix.</param>
        /// <param name="matrix2">Source Matrix matrix.</param>
        /// <returns>A Matrix structure that is the product of two matrices.</returns>
        public static Matrix Multiply(Matrix matrix1, Matrix matrix2)
        {
            Matrix result;

            result.m11 = matrix1.Row1 * matrix2.Col1;
            result.m12 = matrix1.Row1 * matrix2.Col2;
            result.m13 = matrix1.Row1 * matrix2.Col3;
            result.m14 = matrix1.Row1 * matrix2.Col4;

            result.m21 = matrix1.Row2 * matrix2.Col1;
            result.m22 = matrix1.Row2 * matrix2.Col2;
            result.m23 = matrix1.Row2 * matrix2.Col3;
            result.m24 = matrix1.Row2 * matrix2.Col4;

            result.m31 = matrix1.Row3 * matrix2.Col1;
            result.m32 = matrix1.Row3 * matrix2.Col2;
            result.m33 = matrix1.Row3 * matrix2.Col3;
            result.m34 = matrix1.Row3 * matrix2.Col4;

            result.m41 = matrix1.Row4 * matrix2.Col1;
            result.m42 = matrix1.Row4 * matrix2.Col2;
            result.m43 = matrix1.Row4 * matrix2.Col3;
            result.m44 = matrix1.Row4 * matrix2.Col4;

            return result;
        }



        #endregion

        #region Rotation
        public static Matrix RotationX(float angle)
        {
            Matrix result = Matrix.Identity;
            float angleCos = (float)Math.Cos(angle);
            float angleSin = (float)Math.Sin(angle);

            result.m11 = 1;
            result.m12 = 0;
            result.m13 = 0;
            result.m14 = 0;

            result.m21 = 0;
            result.m22 = angleCos;
            result.m23 = angleSin;
            result.m24 = 0;

            result.m31 = 0;
            result.m32 = -angleSin;
            result.m33 = angleCos;
            result.m34 = 0;

            result.m41 = 0;
            result.m42 = 0;
            result.m43 = 0;
            result.m44 = 1;

            return result;
        }


        public static Matrix RotationY(float angle)
        {
            Matrix result = Matrix.Identity;
            float angleCos = (float)Math.Cos(angle);
            float angleSin = (float)Math.Sin(angle);

            result.m11 = angleCos;
            result.m12 = 0;
            result.m13 = -angleSin;
            result.m14 = 0;

            result.m21 = 0;
            result.m22 = 1;
            result.m23 = 0;
            result.m24 = 0;

            result.m31 = angleSin;
            result.m32 = 0;
            result.m33 = angleCos;
            result.m34 = 0;

            result.m41 = 0;
            result.m42 = 0;
            result.m43 = 0;
            result.m44 = 1;

            return result;
        }

        public static Matrix RotationZ(float angle)
        {
            Matrix result = Matrix.Identity;
            float angleCos = (float)Math.Cos(angle);
            float angleSin = (float)Math.Sin(angle);

            result.m11 = angleCos;
            result.m12 = angleSin;
            result.m13 = 0;
            result.m14 = 0;

            result.m21 = -angleSin;
            result.m22 = angleCos;
            result.m23 = 0;
            result.m24 = 0;

            result.m31 = 0;
            result.m32 = 0;
            result.m33 = 0;
            result.m34 = 0;

            result.m41 = 0;
            result.m42 = 0;
            result.m43 = 0;
            result.m44 = 1;

            return result;
        }

        #endregion

        #region Scaling
        public static Matrix Scaling(float x, float y, float z)
        {
            Matrix result = Matrix.Identity;

            result.m11 = x;
            result.m22 = y;
            result.m33 = z;

            return result;
        }
        #endregion

        #region Subtraction
        /// <summary>
        /// Subtracts one matrix from another.
        /// </summary>
        /// <param name="matrix1">A Matrix instance on the left side of the subtraction operation.</param>
        /// <param name="matrix2">A Matrix instance on the left side of the subtraction operation.</param>
        /// <returns>A Matrix instance that represents the result of the subtraction.</returns>
        public static Matrix Subtract(Matrix matrix1, Matrix matrix2)
        {
            Matrix result;

            result.m11 = matrix1.m11 - matrix2.m11;
            result.m12 = matrix1.m12 - matrix2.m12;
            result.m13 = matrix1.m13 - matrix2.m13;
            result.m14 = matrix1.m14 - matrix2.m14;

            result.m21 = matrix1.m21 - matrix2.m21;
            result.m22 = matrix1.m22 - matrix2.m22;
            result.m23 = matrix1.m23 - matrix2.m23;
            result.m24 = matrix1.m24 - matrix2.m24;

            result.m31 = matrix1.m31 - matrix2.m31;
            result.m32 = matrix1.m32 - matrix2.m32;
            result.m33 = matrix1.m33 - matrix2.m33;
            result.m34 = matrix1.m34 - matrix2.m34;

            result.m41 = matrix1.m41 - matrix2.m41;
            result.m42 = matrix1.m42 - matrix2.m42;
            result.m43 = matrix1.m43 - matrix2.m43;
            result.m44 = matrix1.m44 - matrix2.m44;

            return result;
        }
        #endregion

        #region ToString
        /// <summary>
        /// Obtains a string representation of the current instance.
        /// </summary>
        /// <returns>String that represents the object.</returns>
        public override string ToString()
        {
            string row1 = M11.ToString() + " " + M12.ToString() + " " + M13.ToString() + " " + M14.ToString();
            string row2 = M21.ToString() + " " + M22.ToString() + " " + M23.ToString() + " " + M24.ToString();
            string row3 = M31.ToString() + " " + M32.ToString() + " " + M33.ToString() + " " + M34.ToString();
            string row4 = M41.ToString() + " " + M42.ToString() + " " + M43.ToString() + " " + M44.ToString();

            return row1 + "\n" + row2 + "\n" + row3 + "\n" + row4;
        }
        #endregion

        #region Translation
        /// <summary>
        /// Creates a Matrix Translation matrix.
        /// </summary>
        /// <param name="vector">Source Vector3 struct.</param>
        /// <returns>Resulting Translation matrix.</returns>
        public static Matrix Translation(Vector3 vector)
        {
            Matrix result = Matrix.Identity;
            result.M41 = vector.X;
            result.M42 = vector.Y;
            result.M43 = vector.Z;
            return result;
        }

        public static Matrix Translation(float x, float y, float z)
        {
            Matrix result = Matrix.Identity;
            result.M41 = x;
            result.M42 = y;
            result.M43 = z;
            return result;
        }

        public static Vector3 GetTranslation(Matrix mat)
        {
            Vector3 result = new Vector3();
            result.X = mat.m41;
            result.Y = mat.m42;
            result.Z = mat.m43;
            return result;
        }
        #endregion

        #region Transpose
        /// <summary>
        /// Transposes a specified matrix.
        /// </summary>
        /// <param name="matrix">The source matrix.</param>
        /// <returns>The transpose of the specified matrix.</returns>
        public static Matrix Transpose(Matrix matrix)
        {
            Matrix result;
            result.m11 = matrix.m11;
            result.m12 = matrix.m21;
            result.m13 = matrix.m31;
            result.m14 = matrix.m41;

            result.m21 = matrix.m12;
            result.m22 = matrix.m22;
            result.m23 = matrix.m32;
            result.m24 = matrix.m42;

            result.m31 = matrix.m13;
            result.m32 = matrix.m23;
            result.m33 = matrix.m33;
            result.m34 = matrix.m43;

            result.m41 = matrix.m14;
            result.m42 = matrix.m24;
            result.m43 = matrix.m34;
            result.m44 = matrix.m44;

            return result;
        }


        /// <summary>
        /// Transposes this matrix.
        /// </summary>
        public void Transpose()
        {
            Matrix result = Transpose(this);
            this = result;
        }
        #endregion

        // Operators

        #region op_Addition
        /// <summary>
        /// Adds two 4x4 matrices.
        /// </summary>
        /// <param name="matrix1">Matrix source matrix.</param>
        /// <param name="matrix2">Matrix source matrix.</param>
        /// <returns>Matrix result matrix.</returns>
        public static Matrix operator +(Matrix matrix1, Matrix matrix2)
        {
            Matrix result;
            result.m11 = matrix1.m11 + matrix2.m11;
            result.m12 = matrix1.m12 + matrix2.m12;
            result.m13 = matrix1.m13 + matrix2.m13;
            result.m14 = matrix1.m14 + matrix2.m14;

            result.m21 = matrix1.m21 + matrix2.m21;
            result.m22 = matrix1.m22 + matrix2.m22;
            result.m23 = matrix1.m23 + matrix2.m23;
            result.m24 = matrix1.m24 + matrix2.m24;

            result.m31 = matrix1.m31 + matrix2.m31;
            result.m32 = matrix1.m32 + matrix2.m32;
            result.m33 = matrix1.m33 + matrix2.m33;
            result.m34 = matrix1.m34 + matrix2.m34;

            result.m41 = matrix1.m41 + matrix2.m41;
            result.m42 = matrix1.m42 + matrix2.m42;
            result.m43 = matrix1.m43 + matrix2.m43;
            result.m44 = matrix1.m44 + matrix2.m44;

            return result;
        }
        #endregion

        #region op_Equality
        /// <summary>
        /// Compares the current instance of a class to another instance to determine whether they are the same.
        /// </summary>
        /// <param name="left">The Matrix structure to the left of the equality operator.</param>
        /// <param name="right">The Matrix structure to the right of the equality operator.</param>
        /// <returns>Value that is true if the objects are the same, or false if they are different.</returns>
        public static bool operator ==(Matrix left, Matrix right)
        {
            return (left.m11 == right.m11 && left.m12 == right.m12 && left.m13 == right.m13 && left.m14 == right.m14 &&
                    left.m21 == right.m21 && left.m22 == right.m22 && left.m23 == right.m23 && left.m24 == right.m24 &&
                    left.m31 == right.m31 && left.m32 == right.m32 && left.m33 == right.m33 && left.m34 == right.m34 &&
                    left.m41 == right.m41 && left.m42 == right.m42 && left.m43 == right.m43 && left.m44 == right.m44);
        }
        #endregion

        #region op_Inequality
        /// <summary>
        /// Compares the current instance of a class to another instance to determine whether they are different.
        /// </summary>
        /// <param name="left">The Matrix structure to the left of the inequality operator.</param>
        /// <param name="right">The Matrix structure to the right of the inequality operator.</param>
        /// <returns>Value that is true if the objects are different, or false if they are the same.</returns>
        public static bool operator !=(Matrix left, Matrix right)
        {
            return !(left.m11 == right.m11 && left.m12 == right.m12 && left.m13 == right.m13 && left.m14 == right.m14 &&
                    left.m21 == right.m21 && left.m22 == right.m22 && left.m23 == right.m23 && left.m24 == right.m24 &&
                    left.m31 == right.m31 && left.m32 == right.m32 && left.m33 == right.m33 && left.m34 == right.m34 &&
                    left.m41 == right.m41 && left.m42 == right.m42 && left.m43 == right.m43 && left.m44 == right.m44);
        }
        #endregion

        #region op_Multiply
        /// <summary>
        /// Determines the product of two matrices.
        /// </summary>
        /// <param name="matrix1">Source Matrix matrix.</param>
        /// <param name="matrix2">Source Matrix matrix.</param>
        /// <returns>A Matrix structure that is the product of two matrices.</returns>
        public static Matrix operator *(Matrix matrix1, Matrix matrix2)
        {
            Matrix result;

            result.m11 = matrix1.Row1 * matrix2.Col1;
            result.m12 = matrix1.Row1 * matrix2.Col2;
            result.m13 = matrix1.Row1 * matrix2.Col3;
            result.m14 = matrix1.Row1 * matrix2.Col4;

            result.m21 = matrix1.Row2 * matrix2.Col1;
            result.m22 = matrix1.Row2 * matrix2.Col2;
            result.m23 = matrix1.Row2 * matrix2.Col3;
            result.m24 = matrix1.Row2 * matrix2.Col4;

            result.m31 = matrix1.Row3 * matrix2.Col1;
            result.m32 = matrix1.Row3 * matrix2.Col2;
            result.m33 = matrix1.Row3 * matrix2.Col3;
            result.m34 = matrix1.Row3 * matrix2.Col4;

            result.m41 = matrix1.Row4 * matrix2.Col1;
            result.m42 = matrix1.Row4 * matrix2.Col2;
            result.m43 = matrix1.Row4 * matrix2.Col3;
            result.m44 = matrix1.Row4 * matrix2.Col4;

            return result;
        }

        public static Vector3 operator *(Matrix matrix, Vector3 vector)
        {
            return vector * matrix;
        }


        /// <summary>
        /// Multiplication of a Vector3 vector with a Matrix matrix.
        /// </summary>
        /// <param name="vector">Source Vector3 vector.</param>
        /// <param name="matrix">Source Matrix vector.</param>
        /// <returns>Resulting Vector3 structure.</returns>
        public static Vector3 operator *(Vector3 v, Matrix M)
        {
            Vector3 result = new Vector3();

            result.X = v.X * M.m11 + v.Y * M.m21 + v.Z * M.m31 + M.m41;
            result.Y = v.X * M.m12 + v.Y * M.m22 + v.Z * M.m32 + M.m42;
            result.Z = v.X * M.m13 + v.Y * M.m23 + v.Z * M.m33 + M.m43;

            return result;
        }




        /// <summary>
        /// 
        /// </summary>
        /// <param name="matrix"></param>
        /// <param name="vector"></param>
        /// <returns></returns>
        public static Vector4 operator *(Matrix matrix, Vector4 vector)
        {
            return vector * matrix;
        }

        /// <summary>
        /// Multiplication of a Vector4 vector with a Matrix matrix.
        /// </summary>
        /// <param name="vector">Source Vector4 vector.</param>
        /// <param name="matrix">Source Matrix vector.</param>
        /// <returns>Resulting Vector4 structure.</returns>
        public static Vector4 operator *(Vector4 v, Matrix M)
        {
            Vector4 result = new Vector4();

            result.X = M.m11 * v.X + M.M21 * v.Y + M.m31 * v.Z + M.m41 * v.W;
            result.Y = M.m12 * v.X + M.M22 * v.Y + M.m32 * v.Z + M.m42 * v.W;
            result.Z = M.m13 * v.X + M.M23 * v.Y + M.m33 * v.Z + M.m43 * v.W;
            result.W = M.m14 * v.X + M.M24 * v.Y + M.m34 * v.Z + M.m44 * v.W;


            return result;
        }

        /// <summary>
        /// Multiplies a matrix with a single value
        /// </summary>
        /// <param name="matrix1">Source Matrix matrix.</param>
        /// <param name="matrix2">Source Matrix matrix.</param>
        /// <returns>A Matrix structure that is the product of two matrices.</returns>
        public static Matrix operator *(float value, Matrix matrix)
        {
            Matrix result;

            result.m11 = value * matrix.m11;
            result.m12 = value * matrix.m12;
            result.m13 = value * matrix.m13;
            result.m14 = value * matrix.m14;
            result.m21 = value * matrix.m21;
            result.m22 = value * matrix.m22;
            result.m23 = value * matrix.m23;
            result.m24 = value * matrix.m24;
            result.m31 = value * matrix.m31;
            result.m32 = value * matrix.m32;
            result.m33 = value * matrix.m33;
            result.m34 = value * matrix.m34;
            result.m41 = value * matrix.m41;
            result.m42 = value * matrix.m42;
            result.m43 = value * matrix.m43;
            result.m44 = value * matrix.m44;

            return result;
        }


        #endregion

        #region op_Subtraction
        /// <summary>
        /// Subtracts two instances of the Matrix structure.
        /// </summary>
        /// <param name="matrix1">The Matrix structure to the left of the subtraction operator.</param>
        /// <param name="matrix2">The Matrix structure to the right of the subtraction operator.</param>
        /// <returns>Resulting Matrix structure.</returns>
        public static Matrix operator -(Matrix matrix1, Matrix matrix2)
        {
            Matrix result;

            result.m11 = matrix1.m11 - matrix2.m11;
            result.m12 = matrix1.m12 - matrix2.m12;
            result.m13 = matrix1.m13 - matrix2.m13;
            result.m14 = matrix1.m14 - matrix2.m14;
            result.m21 = matrix1.m21 - matrix2.m21;
            result.m22 = matrix1.m22 - matrix2.m22;
            result.m23 = matrix1.m23 - matrix2.m23;
            result.m24 = matrix1.m24 - matrix2.m24;
            result.m31 = matrix1.m31 - matrix2.m31;
            result.m32 = matrix1.m32 - matrix2.m32;
            result.m33 = matrix1.m33 - matrix2.m33;
            result.m34 = matrix1.m34 - matrix2.m34;
            result.m41 = matrix1.m41 - matrix2.m41;
            result.m42 = matrix1.m42 - matrix2.m42;
            result.m43 = matrix1.m43 - matrix2.m43;
            result.m44 = matrix1.m44 - matrix2.m44;

            return result;
        }
        #endregion

    }
}
